"""
命令行接口模块
提供命令行工具的入口点和参数处理
"""
import os
import sys
import logging
import threading
import argparse
from typing import List, Optional, Dict, Any, Union
import json
import time
from pathlib import Path

from tools.web_search import WebSearchTool

sys.stdout.reconfigure(encoding='utf-8')
sys.stderr.reconfigure(encoding='utf-8')
# 获取日志记录器
logger = logging.getLogger(__name__)

# 参数定义和默认值集中配置
DEFAULT_CONFIG = {
    "output_dir": "./results",
    "headless": False,
    "log_level": "info",
    "log_file": None,
    "format": "markdown",
    "extract_mode": "main",
}

# 参数类型定义
PARAM_TYPES = {
    "url": str,
    "output_dir": str,
    "headless": bool,
    "log_level": str,
    "log_file": str,
    "format": str,
    "extract_mode": str,
}

# 参数验证规则
PARAM_VALIDATORS = {
    "url": lambda x: x.startswith(('http://', 'https://')),
    "log_level": lambda x: x in ["debug", "info", "warning", "error", "critical"],
    "format": lambda x: x in ["markdown", "text"],
    "extract_mode": lambda x: x in ["main", "body"],
}

def create_parser() -> argparse.ArgumentParser:
    """创建命令行参数解析器，包含所有参数"""
    parser = argparse.ArgumentParser(
        description="MCP (Web Content Processor) - 网页内容处理工具"
    )
    
    # URL参数组(二选一)
    url_group = parser.add_mutually_exclusive_group(required=True)
    url_group.add_argument(
        "url", 
        nargs='?',
        default=None,
        help="要搜索的网页URL (必须以http://或https://开头)"
    )
    url_group.add_argument(
        "-f", "--file",
        help="包含多个URL的文件，每行一个URL"
    )
    
    # 基本参数
    parser.add_argument(
        "-o", "--output-dir", 
        default=DEFAULT_CONFIG["output_dir"],
        help=f"结果输出目录 (默认: {DEFAULT_CONFIG['output_dir']})"
    )
    
    # 浏览器相关参数
    parser.add_argument(
        "--headless", 
        action="store_true", 
        help="使用无头浏览器模式"
    )
    
    # 并发参数
    parser.add_argument(
        "--workers",
        type=int,
        default=3,
        help="并发工作线程数，用于批量处理多个URL (默认: 3)"
    )
    
    # 日志相关参数
    parser.add_argument(
        "--verbose", 
        action="store_true", 
        help="显示详细日志信息（等同于--log-level debug）"
    )
    parser.add_argument(
        "--log-level", 
        choices=["debug", "info", "warning", "error", "critical"],
        default=None,  # 默认值在后面处理，取决于verbose参数
        help="日志级别: debug, info, warning, error, critical"
    )
    parser.add_argument(
        "--log-file",
        help="日志文件路径，不指定则输出到控制台"
    )
    
    # 输出格式参数
    parser.add_argument(
        "--format", 
        choices=["markdown", "text"],
        default=DEFAULT_CONFIG["format"],
        help=f"输出格式：markdown(默认)或text"
    )
    parser.add_argument(
        "--extract-mode", 
        choices=["main", "body"],
        default=DEFAULT_CONFIG["extract_mode"],
        help=f"内容提取模式：main(主内容区，默认)或body(整个body区域)"
    )
    
    return parser

def validate_args(args: argparse.Namespace) -> Dict[str, str]:
    """
    验证命令行参数
    
    参数:
        args: 解析后的参数命名空间
        
    返回:
        如果有错误，返回错误信息字典；否则返回空字典
    """
    errors = {}
    
    # 验证URL或URL文件
    if args.url and not args.url.startswith(('http://', 'https://')):
        errors['url'] = "URL必须以http://或https://开头"
    
    # 验证URL文件
    if args.file:
        if not os.path.isfile(args.file):
            errors['file'] = f"URL文件不存在: {args.file}"
        else:
            # 检查文件内容
            try:
                with open(args.file, 'r', encoding='utf-8') as f:
                    urls = [line.strip() for line in f if line.strip()]
                if not urls:
                    errors['file'] = f"URL文件为空: {args.file}"
                else:
                    # 检查每个URL的格式
                    invalid_urls = [url for url in urls if not url.startswith(('http://', 'https://'))]
                    if invalid_urls:
                        errors['file'] = f"文件中包含{len(invalid_urls)}个无效URL，第一个: {invalid_urls[0]}"
            except Exception as e:
                errors['file'] = f"无法读取URL文件: {str(e)}"
    
    # 检查并发工作线程数
    if args.workers < 1:
        errors['workers'] = "并发工作线程数必须大于0"
    elif args.workers > 10:
        logger.warning(f"设置了较高的并发数({args.workers})，可能导致性能问题")
    
    # 如果指定了日志文件，检查路径是否可写
    if args.log_file:
        log_dir = os.path.dirname(args.log_file)
        if log_dir and not os.path.exists(log_dir):
            try:
                os.makedirs(log_dir)
            except Exception as e:
                errors['log_file'] = f"无法创建日志目录: {str(e)}"
    
    # 检查输出目录是否可创建/可写
    try:
        output_dir = Path(args.output_dir)
        output_dir.mkdir(parents=True, exist_ok=True)
        test_file = output_dir / ".write_test"
        test_file.touch()
        test_file.unlink()
    except Exception as e:
        errors['output_dir'] = f"输出目录无法写入: {str(e)}"
    
    return errors

def setup_logging(args):
    """
    设置日志系统
    
    参数:
        args: 命令行参数
    """
    # 根据verbose参数确定日志级别
    if args.log_level is None:
        args.log_level = "debug" if args.verbose else "info"
    
    # 映射日志级别
    log_levels = {
        "debug": logging.DEBUG,
        "info": logging.INFO,
        "warning": logging.WARNING,
        "error": logging.ERROR,
        "critical": logging.CRITICAL
    }
    
    # 获取日志级别
    log_level = log_levels.get(args.log_level, logging.DEBUG)
    log_file = args.log_file if hasattr(args, 'log_file') else None
    
    # 如果主入口已配置日志，导入并使用其setup_logging函数
    try:
        from main import setup_logging
        setup_logging(log_level=log_level, log_file=log_file)
        
        # 确保根日志记录器级别已正确设置
        root_logger = logging.getLogger()
        root_logger.setLevel(log_level)
        
        logger.debug(f"使用main.py中的日志配置，级别: {args.log_level}")
        return
    except (ImportError, AttributeError):
        pass
    
    # 在主入口文件已经配置过日志的情况下，仅更新日志级别
    root_logger = logging.getLogger()
    if root_logger.handlers:
        root_logger.setLevel(log_level)
        logger.debug(f"更新日志级别: {args.log_level}")
    else:
        # 主入口没有配置日志，则在这里完整配置
        from pathlib import Path
        import os
        
        # 基本配置
        log_config = {
            'format': '[%(asctime)s][%(process)d][%(thread)d][%(filename)s:%(lineno)d] %(levelname)s: %(message)s',
            'level': log_level,
            'datefmt': '%Y-%m-%d %H:%M:%S',
        }
        
        # 如果指定了日志文件，添加文件处理
        if log_file:
            log_dir = os.path.dirname(log_file)
            if log_dir and not os.path.exists(log_dir):
                os.makedirs(log_dir)
            log_config['filename'] = log_file
            log_config['filemode'] = 'a'  # 追加模式
        
        logging.basicConfig(**log_config)
        
        # 设置第三方库的日志级别
        logging.getLogger("urllib3").setLevel(logging.WARNING)
        logging.getLogger("selenium").setLevel(logging.WARNING)
        logging.getLogger("bs4").setLevel(logging.WARNING)
        
        logger.debug(f"日志系统初始化完成，级别: {args.log_level}")

def main(args: Optional[List[str]] = None) -> int:
    """
    命令行工具主函数
    
    参数:
        args: 命令行参数列表，如果为None则使用sys.argv
    
    返回:
        退出码，0表示成功，非0表示错误
    """
    process_id = os.getpid()
    thread_id = threading.get_ident()
    
    # 解析命令行参数
    parser = create_parser()
    parsed_args = parser.parse_args(args)
    
    # 立即设置日志系统，放在最前面
    setup_logging(parsed_args)
    
    # 启动日志
    logger.info(f"MCP工具启动 [PID:{process_id}][TID:{thread_id}]")
    
    # 流程性操作使用INFO级别
    logger.info(f"执行命令行操作 [PID:{process_id}][TID:{thread_id}]")
    # 详细参数使用DEBUG级别
    logger.debug(f"参数详情: {parsed_args}")
    
    try:
        # 验证参数
        errors = validate_args(parsed_args)
        if errors:
            for param, error in errors.items():
                logger.error(f"参数错误 [{param}]: {error}")
            print(f"错误: 参数验证失败:\n" + "\n".join([f"- {param}: {error}" for param, error in errors.items()]))
            return 1
        
        # 创建输出目录
        output_dir = Path(parsed_args.output_dir)
        output_dir.mkdir(parents=True, exist_ok=True)
        
        # 创建搜索工具
        search_tool = WebSearchTool(
            headless=parsed_args.headless,
            output_dir=str(output_dir),
            output_format=parsed_args.format,
            extract_mode=parsed_args.extract_mode
        )
        
        # 确定要处理的URL列表
        urls = []
        if parsed_args.url:
            # 单个URL模式
            urls = [parsed_args.url]
        elif parsed_args.file:
            # 从文件读取URL列表
            with open(parsed_args.file, 'r', encoding='utf-8') as f:
                urls = [line.strip() for line in f if line.strip() and line.strip().startswith(('http://', 'https://'))]
            logger.info(f"从文件加载了{len(urls)}个URL: {parsed_args.file}")
        
        # 处理URL
        if len(urls) == 1:
            # 单个URL，直接处理
            logger.info(f"开始处理单个URL: {urls[0]}")
            result = search_tool.search(urls[0])
            
            # 输出结果摘要
            print(f"\n检索完成: {urls[0]}")
            print(f"标题: {result['metadata']['title']}")
            print(f"描述: {result['metadata'].get('description', '无')}")
            print(f"内容长度: {len(result['content'])} 字符")
            print(f"输出格式: {parsed_args.format}")
            print(f"提取模式: {parsed_args.extract_mode}")
            print(f"结果已保存到: {parsed_args.output_dir}")
            
            if parsed_args.format == "markdown":
                extract_mode_suffix = "_body" if parsed_args.extract_mode == "body" else ""
                md_file = f"{result['metadata']['domain']}_{int(time.time())}{extract_mode_suffix}.md"
                print(f"Markdown文件: {os.path.join(parsed_args.output_dir, md_file)}")
        else:
            # 多个URL，使用批量处理
            logger.info(f"开始批量处理{len(urls)}个URL，并发数: {parsed_args.workers}")
            
            # 定义进度回调
            processed = 0
            total = len(urls)
            
            def progress_callback(url, result):
                nonlocal processed
                processed += 1
                print(f"[{processed}/{total}] 已处理: {url} - {result['metadata']['title']}")
            
            # 批量处理
            results = search_tool.batch_search(urls, max_workers=parsed_args.workers, callback=progress_callback)
            
            # 输出总结
            print(f"\n批量处理完成: 共处理{len(urls)}个URL，成功{len(results)}个")
            print(f"所有结果已保存到: {parsed_args.output_dir}")
            
            # 生成汇总文件
            summary_file = output_dir / f"summary_{int(time.time())}.json"
            with open(summary_file, 'w', encoding='utf-8') as f:
                summary = [{
                    "url": result["url"],
                    "title": result["metadata"]["title"],
                    "date": result["metadata"].get("publish_date", ""),
                    "author": result["metadata"].get("author", ""),
                    "content_length": len(result["content"])
                } for result in results]
                json.dump(summary, f, ensure_ascii=False, indent=2)
            print(f"处理汇总已保存到: {summary_file}")
        
        logger.info(f"操作成功完成")
        return 0
        
    except Exception as e:
        # 错误信息使用ERROR级别
        logger.error(f"执行过程中发生错误: {str(e)}", exc_info=True)
        print(f"错误: {str(e)}")
        return 1 